/* $RCSFile: Engine.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.RulesEngine/Engine.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:30  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Web;
using System.Globalization;
using System.Web.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Reflection;

namespace Rewrite.NET
{
	
    #region TraceSwitch for Rewrite
   	#region Base TraceSwitchRW classe that define some usefull properties
	public class ADNTraceSwitchRW : TraceSwitch
	{
        public ADNTraceSwitchRW()
            : base("DefaultTrace","Base Trace Switch for url rewritter")
        { }
        public ADNTraceSwitchRW(string nm, string des)
            : base(nm, des)
        { }
        public string Info{ get{ return string.Format("{0}-{1}",DisplayName,Level);}}
	}
	#endregion Base TraceSwitch classe that define some usefull properties
    public class RewriteTraceSwitch
    {
        static public ADNTraceSwitchRW Sw = new ADNTraceSwitchRW("RewriteTrace", "Trace Switch for url rewritter");
    }
    #endregion TraceSwitch for Rewrite

    public class Engine 
    {
        HttpApplication appl			    =   null;
        EngineConfig conf                   =   null;
        Queue rules			                =	new Queue();
        
        bool BreakOnFirst
        {
            get
            {
                return conf.BreakOnFirst;
            }
        }

        public static string ApplicationPath(System.Web.HttpApplication Appl)
        {    
            return  HttpRuntime.AppDomainAppVirtualPath == "/" ? string.Empty : HttpRuntime.AppDomainAppVirtualPath;      
        } 

        public static string Getpath(System.Web.HttpApplication Appl) 
        {
			return Appl.Request.RawUrl;
        }

        public Engine(HttpApplication Appl) 
        {
            appl			        =	Appl;
            conf                    =   EngineConfig.GetConfig();
            if ( conf.Rules.Count == 0 )
            {
	            if ( RewriteTraceSwitch.Sw.TraceError )
                    Trace.WriteLine("[E]Engine Ctor config not found.",RewriteTraceSwitch.Sw.Info);
                return;
            }

            if ( RewriteTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Engine Ctor rules count: {0}, BreakOnFirst: {1}.", conf.Rules.Count,BreakOnFirst),RewriteTraceSwitch.Sw.Info);
            SortedList<string,Assembly> AssemLst    =   new SortedList<string,Assembly>(conf.Rules.Count);
            foreach (IndexRule eRule in conf.Rules)
            {
                string progid       =   eRule.Class.Trim();
                string asmname      =   eRule.Assembly.Trim();
                string filePath     =   HttpRuntime.BinDirectory + asmname + ".dll";
	            if ( RewriteTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Engine Ctor loading filePath: '{0}'", filePath),RewriteTraceSwitch.Sw.Info);
                if (progid != string.Empty && asmname != string.Empty && System.IO.File.Exists(filePath))
                {
                    Assembly asm    =   null;
                    // avoid reloading same assembly several times
                    if (AssemLst.ContainsKey(asmname))
                    {
                        asm         =   AssemLst[asmname];
                    }
                    else
                    {
                        asm         =   Assembly.LoadFrom(filePath);
                        if ( asm != null )
                            AssemLst.Add(asmname, asm);
	                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Engine Ctor loadFrom ok: {0}",(asm != null)),RewriteTraceSwitch.Sw.Info);
                    }
                    if (asm != null)
                    {
                        IRules rule =   (IRules)asm.CreateInstance(progid, true);
	                    if ( RewriteTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Engine Ctor CreateInstance ok: {0}",(rule != null)),RewriteTraceSwitch.Sw.Info);
                        if (rule != null)
                        {
                            rule.Section        =   eRule;
                            AddRule(rule);
                        }
                    }
                }
            }
           
        }
		
        public bool Execute(ref string r) 
        {
            if( rules == null ) 
                return false;
            bool changed    =   false;
			foreach( IRules rule in rules )
			{
				//if r is string.Empty then lets set it back to the path again.
				//each rule can optionally use its value, but it is needed for the simple rule
				//it is merely used to carry forward the last transformation that was done to the path
				if ( r == string.Empty ) 
					r	    =	Getpath(appl);
                if ( rule.Execute(appl,ref r) )
				    changed	=	true;
				//should we return because we want to break on the first change ?
				if( changed && ( BreakOnFirst || rule.BreakAfter ) ) 
					break;
			}            
            return changed;
        }
        
        /// <summary>
        /// Add a new rule to our engine, its key is the settings section in the web.config
        /// </summary>
        public void AddRule(IRules NewRule) 
        {
            if ( !rules.Contains(NewRule) ) 
				rules.Enqueue(NewRule);
        }
    }
}
